<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3//EN">
<HTML><HEAD>
<TITLE>IBM Visualization Data Explorer Programmer&#39;s Reference</TITLE>

<META HTTP-EQUIV="abstract" CONTENT="IBM Visualization Data Explorer
Programmer&#39;s Reference">
<META HTTP-EQUIV="contact" CONTENT="IBM Visualization Data Explorer
(ibmdx@watson.ibm.com)">
<META HTTP-EQUIV="owner" CONTENT="IBM Visualization Data Explorer
(ibmdx@watson.ibm.com)">
<META HTTP-EQUIV="updated" CONTENT="Tue, 16 Sep 1997 ">
<META HTTP-EQUIV="review" CONTENT="Fri, 14 Aug 1998 ">

<META HTTP-EQUIV="keywords" CONTENT="GRAPHICS VISUALIZATION VISUAL PROGRAM DATA
MINING">
<meta http-equiv="content-type" content="text/html;charset=ISO-8859-1">
</HEAD><BODY BGCOLOR="#FFFFFF">

<A NAME="Top_Of_Page"></A>
<H1>IBM Visualization Data Explorer Programmer&#39;s Reference</H1>
<B>&#91; <A HREF="#Bot_Of_Page">Bottom of Page</A> &#124; <A
HREF="progu034.htm">Previous Page</A> &#124; <A HREF="progu036.htm">Next
Page</A> &#124; <A HREF="../proguide.htm#ToC">Table of Contents</A> &#124; <A
HREF="progu033.htm#PToC11">Partial Table of Contents</A> &#124; <A
HREF="progu344.htm#HDRINDEX_START">Index</A> &#93;</B><HR><P>
<HR>
<H1><A NAME="HDRPARAL" HREF="../proguide.htm#ToC_71">Chapter 10. Writing Modules
for a Parallel Environment</A></H1>
<P><A NAME="PToC12" HREF="../proguide.htm#ToC">Partial Table-of-Contents</A>
<MENU>
<LI><A NAME="PToC_72" HREF="#HDREXMODP">10.1 A Parallel Version of the Add
Module</A>
<LI><A NAME="PToC_73" HREF="progu036.htm#HDREXMODP1">10.2 A Parallel Version of
the AverageCell Module</A>
</MENU><HR><P>
<P>
Writing a "parallel" module involves considerations beyond those
encountered in using the Module Builder.
<A NAME="IDX268"></A>
<A NAME="IDX269"></A>
<A NAME="IDX270"></A>
<HR>
<H2><A NAME="HDREXMODP" HREF="#PToC_72">10.1 A Parallel Version of the Add
Module</A></H2>
<A NAME="IDX271"></A>
<A NAME="IDX272"></A>
<A NAME="IDX273"></A>
<A NAME="IDX274"></A>
<P>
The Add module created in the example in <A HREF="progu025.htm#HDRADDMODX">5.1 ,
"Add Module Example--Add a Number to Every Data Value"</A>
would work correctly on partitioned data because
the code generated by the Module Builder automatically provides
recursive traversal.
However, it would not run in parallel on a parallel-architecture
machine.
To create an "addparallel" module, copy the following files to
the directory you want to work in:
<PRE>
<TT><STRONG>/usr/local/dx/samples/program&#95;guide/Makefile&#95;</STRONG><VAR>workstation</VAR></TT>
<TT><STRONG>/usr/local/dx/samples/program&#95;guide/add_parallel.c</STRONG></TT>
<TT><STRONG>/usr/local/dx/samples/program&#95;guide/addpar.mdf</STRONG></TT>
</PRE>
Now rename the makefile to <TT><STRONG>Makefile</STRONG></TT> and enter
<TT>make add_par</TT>.
<P>
To run this module in Data Explorer (from the directory to which the files were
copied), enter&#58;
<PRE>
dx  -mdf ./addpar.mdf -exec ./dxexec
</PRE>
<P>
This command starts Data Explorer (the <TT><STRONG>addpar.mdf</STRONG></TT> file
tells
the graphical user interface about AddParallel and its inputs
and outputs).
<P>
You can now run any visual program that uses the AddParallel module.
One such program is
<TT><STRONG>/usr/local/dx/samples/program&#95;guide/add_parallel.net</STRONG></TT>
.
<P>
The AddParallel module:
<UL>
<P><LI>Encapsulates the Field-level processing in the subroutine
<TT><STRONG>task</STRONG></TT> in this example.
<P><LI>Calls <TT><STRONG>DXCreateTaskGroup</STRONG></TT> just before recursively
traversing the Object in <TT><STRONG>m&#95;AddParallel</STRONG></TT>.
<P><LI>Adds the tasks for processing the Fields during recursive
traversal by calling <TT><STRONG>DXAddTask</STRONG></TT>.
<P><LI>Calls <TT><STRONG>DXExecuteTaskGroup</STRONG></TT> just after
recursive traversal.
At this point, the tasks that are defined will be scheduled on
multiple processors.
If any of the tasks returns an error, that error will be returned from
<TT><STRONG>DXExecuteTaskGroup</STRONG></TT>.
</UL>
<PRE>
01   #include &lt;dx/dx.h&gt;
02
03   static Error DoAdd(Object o, float x);
04
05   m&#95;AddParallel(Object *in, Object *out)
06   &#123;
07       Object o = NULL;
08       float x;
</PRE>
<P>
Copy the structure of
<TT><STRONG>in&#91;0&#93;</STRONG></TT>.
<PRE>
09       if (!in&#91;0&#93;)
10           DXErrorGoto(ERROR&#95;BAD&#95;PARAMETER, &quot;missing object&quot;);
11       o = DXCopy(in&#91;0&#93;, COPY&#95;STRUCTURE);
12       if (!o)
13           goto error;
</PRE>
<P>
Extract floating-point parameter from
<TT><STRONG>in&#91;1&#93;</STRONG></TT> (default 0).
<PRE>
14       if (!in&#91;1&#93;)
15           x = 0;
16       else if (!DXExtractFloat(in&#91;1&#93;, &x))
17           DXErrorGoto(ERROR&#95;BAD&#95;PARAMETER, &quot;bad addend&quot;);
</PRE>
<P>
Create the task Group, call <TT><STRONG>DoAdd()</STRONG></TT>
for recursive traversal, and then execute the task Group.
<PRE>
18        DXCreateTaskGroup();
19        if (!DoAdd(o, x)) {
20          DXAbortTaskGroup()
21          goto error;
22        }
23        if (!DXExecuteTaskGroup())
24          goto error;
</PRE>
<P>
A successful return or return on error.
<PRE>
25        out&#91;0&#93; = o;
26        return OK;
27
28    error:
29        DXDelete(o);
30        return ERROR;
31    &#125;
32
33
</PRE>
<P>
The argument block for passing parameters to the task routine:
<PRE>
34    struct arg &#123;
35        Field field;
36        float x;
37    &#125;
</PRE>
<P>
The following task routine does the actual work of processing a
Field.
<TT><STRONG>DXAddTask</STRONG></TT> instructs the executive to call this
routine once for each Field.
The executive will pass to <TT><STRONG>task</STRONG></TT> the argument block
pointer that was specified when <TT><STRONG>DXAddTask</STRONG></TT>
itself was called.
<PRE>
01
02   static Error
03   task(Pointer p)
04   &#123;
05       struct arg *arg = (struct arg *)p;
06       Field field;
07       float x, *from, *to;
08       int i, n;
09       Array a;
</PRE>
<P>
Extract the arguments.
<PRE>
10       field = arg-&gt;field;
11       x = arg-&gt;x;
</PRE>
<P>
Extract, typecheck, and get the data from the "data" component.
<PRE>
12       a = (Array) DXGetComponentValue(field, &quot;data&quot;);
13       if (!a)
14           DXErrorReturn(ERROR&#95;MISSING&#95;DATA, &quot;field has no data&quot;);
15       if (!DXTypeCheck(a, TYPE&#95;FLOAT, CATEGORY&#95;REAL, 0))
16           DXErrorReturn(ERROR&#95;BAD&#95;TYPE, &quot;data is not floating point&quot;);
17       from = (float *) DXGetArrayData(a);
</PRE>
<P>
Create a new Array, allocate space to it, and put it in the Field.
<PRE>
18       DXGetArrayInfo(a, &n, NULL, NULL, NULL, NULL);
19       a = DXNewArray(TYPE&#95;FLOAT, CATEGORY&#95;REAL, 0);
20       if (!DXAddArrayData(a, 0, n, NULL))
21           return ERROR;
22       to = (float *) DXGetArrayData(a);
23       DXSetComponentValue(field, &quot;data&quot;, (Object)a);
</PRE>
<P>
The following loop adds <TT><STRONG>x</STRONG></TT> to obtain the result.
<PRE>
24       for (i=0; i&lt;n; i++)
25           to&#91;i&#93; = from&#91;i&#93; + x;
</PRE>
<P>
Clean up the Field.
<PRE>
26           DXChangedComponentValues(field, &quot;data&quot;);
27           DXEndField(field);
28
29           return OK;
30       &#125;
</PRE>
<P>
The recursive traversal routine follows.
Note that at this point (and for each Field) it does not process the
Field but calls <TT><STRONG>DXAddTask</STRONG></TT>, specifying the
routine that will be called in parallel to do the
actual work.
<P>
The Data Explorer programming interface is designed so that, in general, the
programmer does need to use explicit locks.
For information about local and global memory allocation, see
<A HREF="progu057.htm#HDRSTORAL">13.3 , "Memory Allocation"</A>.
<PRE>
01   static
02   Error
03   DoAdd(Object o, float x)
04   &#123;
05       struct arg arg;
06       int i, n;
07       Object oo;
</PRE>
<P>
Determine the class of the object.
<PRE>
08       switch (DXGetObjectClass(o)) &#123;
09
10       case CLASS&#95;FIELD:
</PRE>
<P>Add the task for this Field.
<PRE>
11           arg.field = (Field)o;
12           arg.x = x;
13           if (!DXAddTask(task, &arg, sizeof arg, 0.0))
14               return ERROR;
15           break;
16
17       case CLASS&#95;GROUP:
</PRE>
<P>
Traverse Groups recursively.
<PRE>
18            for (i=0; oo=DXGetEnumeratedMember((Group)o, i, NULL); i++)
19                if (!DoAdd(oo, x))
20                    return ERROR;
21            break;
22        &#125;
23
24        return OK;
25    &#125;
</PRE>
<P><HR><B>&#91; <A HREF="#Top_Of_Page">Top of Page</A> &#124; <A
HREF="progu034.htm">Previous Page</A> &#124; <A HREF="progu036.htm">Next
Page</A> &#124; <A HREF="../proguide.htm#ToC">Table of Contents</A> &#124; <A
HREF="#PToC12">Partial Table of Contents</A> &#124; <A
HREF="progu344.htm#HDRINDEX_START">Index</A> &#93;</B> <br><b>&#91;<a
href="../allguide.htm">Data Explorer Documentation</a>&nbsp;&#124;&nbsp;<a
href="../qikguide.htm">QuickStart Guide</a>&nbsp;&#124;&nbsp;<a
href="../usrguide.htm">User&#39;s Guide</a>&nbsp;&#124;&nbsp;<a
href="../refguide.htm">User&#39;s Reference</a>&nbsp;&#124;&nbsp;<a
href="../proguide.htm">Programmer&#39;s Reference</a>&nbsp;&#124;&nbsp;<a
href="../insguide.htm">Installation and Configuration
Guide</a>&nbsp;&#93;</b><br><p><b>&#91;<a
href="http://www.research.ibm.com/dx">Data Explorer Home
Page</a>&#93;</b><p><HR ALIGN=LEFT WIDTH=600><b>&#91;<A
HREF="http://www.ibm.com/">IBM Home Page</A>&nbsp;&#124;&nbsp;<A
HREF="http://www.ibm.com/Orders/">Order</A>&nbsp;&#124;&nbsp;<A
HREF="http://www.ibm.com/Search/">Search</A>&nbsp;&#124;&nbsp;<A
HREF="http://www.ibm.com/Assist/">Contact IBM</A>&nbsp;&#124;&nbsp;<A
HREF="http://www.ibm.com/Legal/">Legal</A>&nbsp;&#93;</b><hr><p>
<A NAME="Bot_Of_Page"></A>
</BODY></HTML>
